﻿using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using HtmlAgilityPack;
using YougeBookmark.Utilities;
using System.Linq;
using HtmlDocument = HtmlAgilityPack.HtmlDocument;
namespace YougeBookmark.Services
{
    public class HtmlParser
    {
        private readonly HttpClient _httpClient;
        private readonly Logger _logger;

        public HtmlParser(Logger logger)
        {
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));

            _httpClient = new HttpClient(new HttpClientHandler
            {
                AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
                AllowAutoRedirect = true
            });

            _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
            _httpClient.Timeout = TimeSpan.FromSeconds(15);
        }

        public async Task<ParsedHtmlData> Parse(string url)
        {
            try
            {
                // 验证并格式化URL
                if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
                    throw new UriFormatException("无效的URL格式");

                // 获取HTML文档
                var html = await _httpClient.GetStringAsync(uri);
                var doc = new HtmlDocument();
                doc.LoadHtml(html);

                // 解析元数据
                var ogImage = GetMetaContent(doc, "og:image");
                var ogDescription = GetMetaContent(doc, "og:description");
                var metaDescription = GetMetaContent(doc, "description");

                // 构建绝对图片路径
                if (!string.IsNullOrEmpty(ogImage))
                    ogImage = new Uri(uri, ogImage).AbsoluteUri;

                // 智能选择首图（优先OpenGraph，其次首个合规img标签）
                var imageUrl = ogImage ?? FindFirstValidImage(doc, uri);

                // 下载图片数据（限制最大10MB）
                byte[] imageData = null;
                if (!string.IsNullOrEmpty(imageUrl))
                {
                    imageData = await DownloadWithSizeLimitAsync(imageUrl, maxBytes: 10 * 1024 * 1024);
                }

                return new ParsedHtmlData
                {
                    Url = url, // 新增此行
                    Title = WebUtility.HtmlDecode(GetMetaContent(doc, "og:title") ?? doc.DocumentNode.SelectSingleNode("//title")?.InnerText.Trim()),
                    Summary = WebUtility.HtmlDecode(ogDescription ?? metaDescription ?? ExtractFirstMeaningfulText(doc)),
                    ImageUrl = imageUrl,
                    ImageData = imageData
                };
            }
            catch (Exception ex)
            {
                _logger.Error($"HTML解析失败: {url} - {ex.Message}", ex);
                return null;
            }
        }

        private string GetMetaContent(HtmlDocument doc, string propertyName)
        {
            return doc.DocumentNode.SelectSingleNode(
                $"//meta[@{(propertyName.Contains(':') ? "property" : "name")}='{propertyName}']")?
                .GetAttributeValue("content", null)?
                .Trim();
        }

        private string FindFirstValidImage(HtmlDocument doc, Uri baseUri)
        {
            var imgNodes = doc.DocumentNode.SelectNodes("//img[@src]");
            if (imgNodes == null) return null;

            foreach (var node in imgNodes)
            {
                var src = node.GetAttributeValue("src", null);
                if (string.IsNullOrWhiteSpace(src)) continue;

                try
                {
                    // 排除base64内嵌图片和跟踪像素
                    if (src.StartsWith("data:image") || src.Contains("tracking-pixel")) continue;

                    var imgUri = new Uri(baseUri, src);
                    if (imgUri.Scheme == Uri.UriSchemeHttp || imgUri.Scheme == Uri.UriSchemeHttps)
                        return imgUri.AbsoluteUri;
                }
                catch (UriFormatException)
                {
                    continue;
                }
            }
            return null;
        }

        //private async Task<byte[]> DownloadWithSizeLimitAsync(string url, int maxBytes)
        //{
        //    using var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
        //    if (!response.IsSuccessStatusCode) return null;

        //    var contentLength = response.Content.Headers.ContentLength ?? 0;
        //    if (contentLength > maxBytes) return null;

        //    using var stream = await response.Content.ReadAsStreamAsync();
        //    var buffer = new byte[maxBytes];
        //    var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
        //    return buffer.Take(bytesRead).ToArray();
        //}

        private async Task<byte[]> DownloadWithSizeLimitAsync(string url, int maxBytes)
        {
            using var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
            if (!response.IsSuccessStatusCode) return null;

            var contentLength = response.Content.Headers.ContentLength ?? 0;
            if (contentLength > maxBytes) return null;

            using var stream = await response.Content.ReadAsStreamAsync();
            using var memoryStream = new MemoryStream();
            var buffer = new byte[4096]; // 4KB 缓冲区
            int totalBytesRead = 0;

            while (true)
            {
                // 每次最多读取剩余允许的字节数
                var bytesToRead = Math.Min(buffer.Length, maxBytes - totalBytesRead);
                var bytesRead = await stream.ReadAsync(buffer, 0, bytesToRead);

                if (bytesRead == 0) break; // 流结束

                memoryStream.Write(buffer, 0, bytesRead);
                totalBytesRead += bytesRead;

                // 达到限制时立即停止
                if (totalBytesRead >= maxBytes) break;
            }

            return memoryStream.ToArray();
        }

        private string ExtractFirstMeaningfulText(HtmlDocument doc)
        {
            var candidates = new[]
            {
                "//p[not(ancestor::footer)][string-length() > 100]",
                "//div[contains(@class, 'content')]",
                "//article"
            };

            foreach (var xpath in candidates)
            {
                var node = doc.DocumentNode.SelectSingleNode(xpath);
                var text = node?.InnerText?.Trim();
                if (!string.IsNullOrEmpty(text) && text.Length > 50)
                {
                    return WebUtility.HtmlDecode(text.Substring(0, Math.Min(300, text.Length)) + "...");
                }
            }
            return null;
        }
    }

    public class ParsedHtmlData
    {
        public string Title { get; set; }
        public string Summary { get; set; }
        public string Url { get; set; } // 新增属性
        public string ImageUrl { get; set; }
        public byte[] ImageData { get; set; }
    }
}